package com.gzhryc.jdbc.proxy;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.reflect.FieldUtils;

import com.gzhryc.jdbc.utils.EntityUtils;

/**
 * 数据结构代理
 * @author 张浩
 * @version 1.0.2
 */
public abstract class ModelProxy {

	protected final Object obj;
	protected final String tableName;
	protected final Field idField;
	
	protected LinkedHashMap<String,Object> updateFields = new LinkedHashMap<String,Object>();
	
	protected Pattern pat = Pattern.compile("^set(.*)$");

	public ModelProxy(Object obj){
		this.tableName = EntityUtils.getTableName(obj.getClass());
		this.idField = EntityUtils.getIdField(obj.getClass());
		this.obj = obj;
	}
	
	public abstract<T> T wrap();
	
	/**
	 * 被代理类方法执行前调用
	 * @param method
	 * @param args
	 */
	protected void before(Method method,Object[] args){
		Matcher mat = pat.matcher(method.getName());
		if(mat.find()){
			String fieldName = mat.group(1);
			fieldName = fieldName.substring(0, 1).toLowerCase()+fieldName.substring(1).toLowerCase();
			Field field = FieldUtils.getDeclaredField(getObjectClass(), fieldName);
			if(field != null){
				try {
					field.setAccessible(true);
					Object oldVal = field.get(obj);
					if(oldVal == null){
						if(args[0] != null){
							updateFields.put(fieldName, args[0]);
						}
					}else if(args[0]  == null || !oldVal.equals(args[0])){
						updateFields.put(fieldName, args[0]);
					}
					
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 获取被代理的类类型
	 * @return
	 */
	public Class<?> getObjectClass(){
		return obj.getClass();
	}
	
	/**
	 * 获取被代理的对象
	 * @return
	 */
	public Object getObject(){
		return obj;
	}
	
	public LinkedHashMap<String,Object> getUpdateFields() {
		return updateFields;
	}
	
	public static<T> ModelProxy create(T obj){
		Class<?>[] interfaces = obj.getClass().getInterfaces();
		boolean isJDKProxy = false;
		if(interfaces.length > 0){
			for(int i=0;i<interfaces.length;i++){
				if((!interfaces[i].equals(Serializable.class))){
					isJDKProxy = true;
					break;
				}
			}
		}
		
		if(isJDKProxy){
			return new ModelJDKProxy(obj);
		}else{
			return new ModelCGLIBProxy(obj);
		}
	}

	
}